<template>
  <div class="smart-upload">
    <el-upload
      v-if="!currentFile"
      ref="uploadRef"
      v-bind="mergedAttrs"
      :class="['uploader', { 'is-disabled': disabled }]"
      :file-list="fileList"
      :on-change="handleChange"
      :on-remove="handleRemove"
      :before-upload="beforeUpload"
    >
      <!-- <template #trigger>
        <div class="upload-area">
          <el-icon class="el-icon--upload"><upload-filled /></el-icon>
          <div class="el-upload__text">{{ uploadText }}</div>
        </div>
      </template> -->
      <el-icon class="el-icon--upload"><upload-filled /></el-icon>
      <div class="el-upload__text">将{{ uploadText }}拖到此处，或<em>点击上传</em></div>
      <template #tip>
        <div class="el-upload__tip">{{ tipText }}</div>
      </template>
    </el-upload>

    <!-- 智能预览区域 -->
    <div v-if="shouldShowPreview" class="preview-container">
      <!-- 图片预览 -->
      <img v-if="inferredType === 'image' && previewUrl" :src="previewUrl" class="preview-image" />

      <!-- 视频预览 -->
      <video
        v-else-if="inferredType === 'video' && previewUrl"
        :src="previewUrl"
        controls
        class="preview-video"
      ></video>

      <!-- 音频预览 -->
      <div v-else-if="inferredType === 'audio' && currentFile" class="preview-audio">
        <el-icon><Headset /></el-icon>
        <span>{{ currentFile.name }}</span>
        <span>({{ formatFileSize(currentFile.size) }})</span>
      </div>

      <!-- 通用文件预览 -->
      <div v-else-if="currentFile" class="preview-generic">
        <el-icon><Document /></el-icon>
        <div class="file-info">
          <span class="file-name">{{ currentFile.name }}</span>
          <span class="file-size">{{ formatFileSize(currentFile.size) }}</span>
          <span class="file-type">{{ currentFile.type || "未知类型" }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onBeforeUnmount } from "vue";
import { UploadFilled, Headset, Document } from "@element-plus/icons-vue";
import Compressor from "compressorjs";
import { updateFile } from "@/api/file";
const props = defineProps({
  modelValue: [Object, Array, String],
  accept: {
    type: String,
    default: "*/*",
  },
  maxSize: {
    type: Number,
    default: 10,
  },
  limit: {
    type: Number,
    default: 1,
  },
  compress: {
    type: [Boolean, Object],
    default: false,
  },
  disabled: Boolean,
  autoUpload: {
    type: Boolean,
    default: false,
  },
  // 新增：显式控制是否显示预览（优先级高于自动推断）
  showPreview: {
    type: Boolean,
    default: null, // null表示自动推断
  },
});

const emit = defineEmits(["update:modelValue", "change", "invalid", "success", "error"]);

const attrs = useAttrs();
const uploadRef = ref();
const currentFile = ref(null);
const previewUrl = ref("");
const isLoading = ref(false);

// 根据accept自动推断文件类型
const inferredType = computed(() => {
  const accept = props.accept.toLowerCase();

  if (accept.includes("image/")) return "image";
  if (accept.includes("video/")) return "video";
  if (accept.includes("audio/")) return "audio";

  // 根据常见扩展名推断
  const imageExts = [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"];
  const videoExts = [".mp4", ".avi", ".mov", ".wmv", ".flv"];
  const audioExts = [".mp3", ".wav", ".ogg", ".m4a"];

  if (imageExts.some((ext) => accept.includes(ext))) return "image";
  if (videoExts.some((ext) => accept.includes(ext))) return "video";
  if (audioExts.some((ext) => accept.includes(ext))) return "audio";

  return "file"; // 默认通用文件类型
});

// 自动推断是否需要预览
const shouldShowPreview = computed(() => {
  // 如果显式设置了showPreview，则优先使用
  if (props.showPreview !== null) return props.showPreview;

  // 自动推断：图片、视频、音频需要预览，其他不需要
  return ["image", "video", "audio"].includes(inferredType.value);
});

// 合并属性
const mergedAttrs = computed(() => ({
  action: "#",
  autoUpload: false,
  showFileList: false,
  multiple: props.limit > 1,
  ...attrs,
  limit: props.limit,
  accept: props.accept,
  disabled: props.disabled || isLoading.value,
}));

const uploadText = computed(() => {
  const typeMap = {
    image: "图片",
    video: "视频",
    audio: "音频",
    file: "文件",
  };
  const typeName = typeMap[inferredType.value] || "文件";

  return props.limit > 1
    ? `上传${typeName} (${props.modelValue?.length || 0}/${props.limit})`
    : `上传${typeName}`;
});

const tipText = computed(() => {
  const typeMap = {
    image: "图片",
    video: "视频",
    audio: "音频",
    file: "文件",
  };
  const typeName = typeMap[inferredType.value] || "文件";

  let acceptText =
    props.accept === "*/*"
      ? "所有格式"
      : props.accept
          .split(",")
          .map((ext) => ext.trim().replace(".", "").toUpperCase())
          .join("/");

  return `支持${acceptText}格式的${typeName}，大小不超过${props.maxSize}MB`;
});

const fileList = computed(() => {
  if (!props.modelValue) return [];

  return Array.isArray(props.modelValue)
    ? props.modelValue.map((file) => normalizeFile(file))
    : [normalizeFile(props.modelValue)];
});

const normalizeFile = (file) => {
  if (typeof file === "string") {
    return {
      name: file.split("/").pop() || "已上传文件",
      url: file,
    };
  }
  return {
    name: file.name,
    size: file.size,
    type: file.type,
    raw: file,
    url: file.url || (file instanceof File ? URL.createObjectURL(file) : ""),
  };
};

const beforeUpload = (file) => {
  if (!validateFileType(file)) {
    emit("invalid", { type: "format", file });
    return false;
  }

  if (!validateFileSize(file)) {
    emit("invalid", { type: "size", file });
    return false;
  }

  return true;
};

const validateFileType = (file) => {
  if (props.accept === "*/*") return true;

  const acceptedTypes = props.accept.split(",").map((ext) => ext.trim().toLowerCase());

  // 检查文件扩展名
  const fileExt = file.name.split(".").pop().toLowerCase();
  if (acceptedTypes.some((type) => type.endsWith(fileExt))) {
    return true;
  }

  // 检查MIME类型
  if (file.type && acceptedTypes.some((type) => type.includes(file.type.split("/")[1]))) {
    return true;
  }

  // 检查通配类型（如image/*）
  if (
    acceptedTypes.some((type) => type.includes("*") && file.type.startsWith(type.split("/*")[0]))
  ) {
    return true;
  }

  return false;
};

const validateFileSize = (file) => file.size <= props.maxSize * 1024 * 1024;

const handleChange = async (uploadFile, uploadFiles) => {
  try {
    const files = uploadFiles.map((file) => file.raw);
    currentFile.value = files[0];

    // 生成预览URL（仅图片和视频需要）
    if (["image", "video"].includes(inferredType.value)) {
      if (previewUrl.value) URL.revokeObjectURL(previewUrl.value);
      previewUrl.value = URL.createObjectURL(files[0]);
    }

    // 压缩处理
    let processedFiles = files;
    if (props.compress && shouldCompress(files[0])) {
      processedFiles = await Promise.all(
        files.map((file) => (props.compress ? processCompression(file) : file))
      );
    }

    // 自动上传
    if (props.autoUpload) {
      isLoading.value = true;
      const res = await submitFiles(processedFiles);
      emit("update:modelValue", res.data);
      emit("success", res);
    } else {
      const value = props.limit > 1 ? processedFiles : processedFiles[0];
      emit("update:modelValue", value);
      emit("change", value);
    }
  } catch (err) {
    emit("error", err);
  } finally {
    isLoading.value = false;
  }
};

const shouldCompress = (file) => {
  // 只压缩图片类型
  return file.type.startsWith("image/");
};

const processCompression = (file) => {
  return new Promise((resolve, reject) => {
    new Compressor(file, {
      quality: 0.6,
      ...(typeof props.compress === "object" ? props.compress : {}),
      success(result) {
        resolve(
          new File([result], file.name, {
            type: result.type,
            lastModified: Date.now(),
          })
        );
      },
      error(err) {
        reject(new Error(`压缩失败: ${err.message}`));
      },
    });
  });
};

const handleRemove = () => {
  if (previewUrl.value) URL.revokeObjectURL(previewUrl.value);
  previewUrl.value = "";
  currentFile.value = null;
  emit("update:modelValue", props.limit > 1 ? [] : null);
};

const submitFiles = async (files) => {
  if (files.length === 0) throw new Error("请先上传文件");

  const formData = new FormData();
  if (props.limit > 1) {
    files.forEach((file) => formData.append("files[]", file));
  } else {
    formData.append("file", files[0]);
  }
 try {
    const res = await updateFile(formData);
    ElMessage.success("上传成功");
    return res; // 正确返回结果
  } catch (error) {
    currentFile.value = null;
    throw error; // 重新抛出错误
  }
};

// 暴露方法
defineExpose({
  submit: async () => {
    if (!props.modelValue) throw new Error("请先上传文件");

    const files = props.limit > 1 ? props.modelValue : [props.modelValue];

    isLoading.value = true;
    try {
      const res = await submitFiles(files);
      emit("success", res);
      return res;
    } finally {
      isLoading.value = false;
    }
  },
  clear: () => {
    uploadRef.value?.clearFiles();
    handleRemove();
  },
  getCurrentFile: () => currentFile.value,
});

// 清理
onBeforeUnmount(() => {
  if (previewUrl.value) URL.revokeObjectURL(previewUrl.value);
});

// 辅助函数
const formatFileSize = (bytes) => {
  if (!bytes) return "0 Bytes";
  const k = 1024;
  const sizes = ["Bytes", "KB", "MB", "GB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
};
</script>

<style scoped>
.smart-upload {
  width: 100%;
}

.uploader {
  width: 100%;
}

.upload-area {
  padding: 40px 0;
  text-align: center;
}

.preview-container {
  margin-top: 20px;
  text-align: center;
}

.preview-image {
  max-width: 100%;
  max-height: 300px;
  border: 1px solid #eee;
  border-radius: 4px;
}

.preview-video {
  max-width: 100%;
  max-height: 300px;
  background: #000;
  border-radius: 4px;
}

.preview-audio {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 15px;
  background: #f8f9fa;
  border-radius: 4px;
}

.preview-audio .el-icon {
  font-size: 24px;
  color: #409eff;
}

.preview-generic {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  background: #f8f9fa;
  border-radius: 4px;
  text-align: left;
}

.preview-generic .el-icon {
  font-size: 36px;
  color: #909399;
}

.file-info {
  display: flex;
  flex-direction: column;
}

.file-name {
  font-weight: 500;
  margin-bottom: 4px;
}

.file-size,
.file-type {
  font-size: 12px;
  color: #909399;
}

.el-upload__tip {
  color: var(--el-text-color-secondary);
  font-size: 12px;
  margin-top: 7px;
  /* text-align: center; */
}
</style>
